/*
 * Created on 2006-3-15
 *
 * TODO To change the template for this generated file go to
 * Window - Preferences - Java - Code Style - Code Templates
 */
package auditoryUIbk;
import java.awt.Polygon;
import java.awt.Rectangle;
import java.awt.Point;
//import java.awt.Point;
import java.io.Serializable;
import java.util.*;

public class TimedPolygon extends Polygon
  implements Serializable, Cloneable
{
  // in the tradition of Polygon, make this public
  public long[] times;
  
  private ArrayList angles = new ArrayList(); //angular value
  
  private ArrayList turningPoints = new ArrayList();

  public TimedPolygon()
  {
	super();
	times = new long[4];
	//angles = new ArrayList();
  }

  public TimedPolygon(int[] x, int[] y, int numPoints)
  {
	this(x, y, System.currentTimeMillis(), numPoints);
  }
  
  public TimedPolygon(int[] x, int[] y, long time, int numPoints)
  {
	super(x, y, numPoints);
	times = new long[numPoints];
	for (int i = 0; i < numPoints; i++) {
	  times[i] = time;
	}
  }
  
  public TimedPolygon(int[] x, int[] y, long[] t, int numPoints)
  {
	super(x, y, numPoints);
	times = new long[t.length];
	System.arraycopy(t, 0, times, 0, npoints);	
  }

  public TimedPolygon(Polygon p)
  {
	this(p.xpoints, p.ypoints, p.npoints);
  }
  
  public TimedPolygon(TimedPolygon p)
  {
	this(p.xpoints, p.ypoints, p.times, p.npoints);
  }
  
  public void addAngle(double angleValue){
  		angles.add(new Double(angleValue));
  }
  
  /**
   * Get the angle value for the polygon
   * 
   * @param pos
   * @return
   */
  public double getAngleAt(int pos){
  	if(pos < angles.size() && pos > -1){
  		Double dValue = (Double) angles.get(pos);
  		return dValue.doubleValue();
  	}
  	else{
  		return -1.0;
  	}
  }
  
  public void addPoint(int x, int y)
  {
	addPoint(x, y, System.currentTimeMillis());
  }

  public void addPoint(int x, int y, long t)
  {
	super.addPoint(x, y);

	if (npoints == times.length) {
	  // resize the times array
	  long[] temp = new long[times.length * 2];
	  System.arraycopy(times, 0, temp, 0, times.length);
	  times = temp;
	}

	times[npoints-1] = t;
  }

  public Object clone()
  {
	try {
	  TimedPolygon result = (TimedPolygon) super.clone();
	  result.xpoints = (int[]) xpoints.clone();
	  result.ypoints = (int[]) ypoints.clone();
	  result.times = (long[]) times.clone();
	  if (bounds != null) {
	result.bounds = (Rectangle) bounds.clone();
	  }
	  return result;
	}
	catch (CloneNotSupportedException e) {
	  return null;
	}
  }
  
  public void calculateAngles(){
	int[] xs = xpoints;
		int[] ys = ypoints;
	
		for(int i=0; i< npoints-1; i++){
			//G.debug("draw line");
			//gg.drawLine(xs[i],ys[i],xs[i+1],ys[i+1]);	
			PolarCoordinate polar = SimpleStrokeAudioUIbk._getPolarCoordinates(xs[i], ys[i], xs[i+1], ys[i+1]);
			addAngle(Math.toDegrees(polar.theta));
			//G.debug("angle is "+ Math.toDegrees(polar.theta));
		}
  }
  
  public void calculateTurningPoints(int size){
  	//turningPoints = new ArrayList();
  	
  	double delta = 25.0;
  	int timeThreshold = 0;
  	if(size == 0){
  		//big
  		delta = 25.0;
  		timeThreshold = 200;
  	}
  	else if(size == 1){
  		//medium size
  		delta = 25.0;
  		timeThreshold = 200;
  	}
  	else if(size == 2){
  		delta = 25.0;
  		timeThreshold = 200;
  	}
  	
	turningPoints.add(new Point(xpoints[0], ypoints[0]));
	double lastAvgAngle = getAngleAt(0);
	
	//besides angle, we also check for major time differences
	long lastTimePoint = times[0];
	
	int lastTurningPosition = 0;
	
	//if major angle difference presents, we will record that
	//as a turning point, otherwise we also check for time differences
	//if there is a major time gap say > 200 milliseconds, we will
	//record that as a time gap
  	for(int i=1; i< angles.size(); i++){
  		//the first point is always one of the turning point
  		double newAngle = getAngleAt(i);
  		if(newAngle > (lastAvgAngle + delta) || newAngle < (lastAvgAngle - delta)){
  			if((360.0 -Math.abs(newAngle - lastAvgAngle)) < delta){
  				//need to check time for the points if the angle test is not working
  				//if timing position is equal the next point of the last turning point, it might
  				//be the delay due to the turning, we don't want to add the duplicated
  				//point 
				if((times[i]-lastTimePoint) > timeThreshold && Math.abs(i-lastTurningPosition) != 1){
								turningPoints.add(new Point(xpoints[i], ypoints[i]));
								lastTurningPosition = i;
								G.debug("adding time based turing point " + i);
							}
  			}
  			else{
  				turningPoints.add(new Point(xpoints[i], ypoints[i]));
  				lastTurningPosition = i;
  				G.debug("adding angle based turning point" + Math.abs(newAngle - lastAvgAngle)+ " " + i);
  			}
  			lastAvgAngle = newAngle;
  		}
  		else{
  			lastAvgAngle = newAngle;
  			if((times[i]-lastTimePoint) > timeThreshold && Math.abs(i-lastTurningPosition) != 1){
  				turningPoints.add(new Point(xpoints[i], ypoints[i]));
  				lastTurningPosition = i;
  				G.debug("adding time based turing point " + i);
  			}
  			
  		}
  		if(i == angles.size()-1) {
  			turningPoints.add(new Point(xpoints[i], ypoints[i]));
  			G.debug("adding last point as a turning point");
  		}
  		lastTimePoint = times[i];
  	}
  	
  	//once we get the turning points, I need to do some further 
  	//processing to remove the points that's too close to each other
  	ArrayList removablePoints = new ArrayList();
  	for(int i =0; i< turningPoints.size()-1; i++){
  		Point p1 = (Point) turningPoints.get(i);
  		Point p2 = (Point) turningPoints.get(i+1);
  		double distance = G.intPointDistance(p1.x, p1.y, p2.x, p2.y);
  		//G.debug("distance is "+ distance);
  		double threshold = 0.0;
  		//we try to set the threshold so that it will work in the small area
  		if(size == 0){
  			threshold = 15.0;
  			//threshold is 25 before
  		}
  		else if(size == 1){
  			threshold = 8.0;
  		}
  		else if(size == 2){
  			threshold = 4.0;
  			//threshold is 1.0 before
  		}
  		if(distance < threshold) {
  			//I still need to remove these points because
  			//of the jitter
  			removablePoints.add(p1);
  			G.debug("removing point "+p1.toString());
  		} 
  	}
  	if(removablePoints.size() > 0){
  		for(int i=0; i< removablePoints.size(); i++){
  			turningPoints.remove(removablePoints.get(i));
  		}
  	}
  	//turningPoints.add(new Point(xpoints[xpoints.length-1], ypoints[ypoints.length-1]));
  }
  
  public ArrayList getTurningPoints(){
  	return turningPoints;
  }
}